package com.ihr360.cnb.module.insurance.service.impl;

import cn.irenshi.organization.meta.entity.organization.CompanyStructureEntity;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ihr360.cnb.module.common.service.Ihr360StaffApiService;
import com.ihr360.cnb.module.common.service.OrganizationService;
import com.ihr360.cnb.module.insurance.model.StaffDataAuthorityCodeConstants;
import com.ihr360.cnb.module.insurance.model.excel.HeaderConstants;
import com.ihr360.cnb.module.insurance.service.StaffBenefitAggregateService;
import com.ihr360.cnb.module.insurance.service.StaffBenefitImportService;
import com.ihr360.cnb.module.insurance.service.feign.InsuranceService;
import com.ihr360.commons.exception.Ihr360Exception;
import com.ihr360.commons.lang.CollectionUtils;
import com.ihr360.commons.lang.DateUtils;
import com.ihr360.commons.model.type.BenefitCategory;
import com.ihr360.commons.model.type.BenefitsPayer;
import com.ihr360.commons.vo.PageData;
import com.ihr360.entity.BasicStaffInfoEntity;
import com.ihr360.excel.ExcelUtil;
import com.ihr360.excel.cellstyle.ExcelCellStyle;
import com.ihr360.excel.cellstyle.ExcelCellStyleFactory;
import com.ihr360.excel.entity.CellComment;
import com.ihr360.excel.entity.ExportParams;
import com.ihr360.excel.utils.SpreadSheetConvertResultUtil;
import com.ihr360.excel.vo.CustomSpreadSheetValidateResult;
import com.ihr360.excel.vo.ImportRequest;
import com.ihr360.excel.vo.SpreadSheetCell;
import com.ihr360.excel.vo.SpreadSheetRow;
import com.ihr360.excel.vo.SpreadSheetValidatorError;
import com.ihr360.excel.vo.SpreadSheetValidatorRequest;
import com.ihr360.insurance.entity.request.StaffBenefitRequest;
import com.ihr360.insurance.entity.request.StaffIdRequest;
import com.ihr360.insurance.entity.vo.BenefitVo;
import com.ihr360.insurance.entity.vo.CompanyBenefitSimpleVo;
import com.ihr360.insurance.entity.vo.StaffBenefitVo;
import com.ihr360.validation.ValidationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Nonnull;
import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Stone.Shi
 * @description
 * @date 2018-05-30 10:54:55.
 */
@Service
public class StaffBenefitImportServiceImpl implements StaffBenefitImportService {

    private Logger logger = LoggerFactory.getLogger(InsuranceAggregateServiceImpl.class);

    private static Map<String, Boolean> calculates = Maps.newLinkedHashMap();
    private static Map<Boolean, String> calculatableNameMap = Maps.newLinkedHashMap();
    private static Map<String, BenefitsPayer> payers = Maps.newLinkedHashMap();
    private static List<String> calculateList;
    private static List<String> payerTitles;

    static {
        calculates.put("是", Boolean.TRUE);
        calculates.put("否", Boolean.FALSE);
        calculatableNameMap.put(Boolean.TRUE, "是");
        calculatableNameMap.put(Boolean.FALSE, "否");
        calculateList = Lists.newArrayList(calculates.keySet());
        payers.put(BenefitsPayer.PERSON.getTitle(), BenefitsPayer.PERSON);
        payers.put(BenefitsPayer.COMPANY.getTitle(), BenefitsPayer.COMPANY);
        payerTitles = Lists.newArrayList(payers.keySet());
    }

    @Autowired
    private Ihr360StaffApiService staffApiService;

    @Autowired
    private OrganizationService organizationService;

    @Autowired
    private InsuranceService insuranceService;

    @Autowired
    private StaffBenefitAggregateService staffBenefitAggregateService;

    @Override
    public void downloadTemplateExcel(String companyId, ServletOutputStream outputStream) {

        ExportParams exportParams = new ExportParams();
        Map<String, String> headerMap = getTemplateHeaderMap(false);
        exportParams.setHeaderMap(headerMap);

        Map<String, ExcelCellStyle> headerStyleMap = getHeaderStyleMap();
        exportParams.setHeaderStyleMap(headerStyleMap);

        Map<String, CellComment> headerCommentMap = getHeaderCommentMap();
        exportParams.setHeaderCommentMap(headerCommentMap);

        Map<String, List<String>> dropDownsMap = getDropDownsMap(companyId);
        exportParams.setDropDownsMap(dropDownsMap);

        ExcelUtil.exportExcel(exportParams, outputStream);
        try {
            outputStream.close();
        } catch (IOException e) {
            logger.error("模板下载失败：" + e);
            throw new Ihr360Exception("", "模板下载失败！");
        }
    }

    private Map<String, CellComment> getHeaderCommentMap() {
        Map<String, CellComment> headerCommentMap = Maps.newHashMap();
        CellComment mobileCellComment = CellComment.createDefaultCellComment("存在姓名相同的员工，各自的手机号必须填写，且不能相同");
        headerCommentMap.put(HeaderConstants.ID_MOBILE_NO, mobileCellComment);

        CellComment baseCellComment = CellComment.createDefaultCellComment("最多两位小数（如多于两位小数，将按照两位小数截取处理）");
        headerCommentMap.put(HeaderConstants.ID_SI_BASE, baseCellComment);
        headerCommentMap.put(HeaderConstants.ID_HF_BASE, baseCellComment);

        CellComment stardOnCellComment = CellComment.createDefaultCellComment("年-月：如2018-01（如填写年月日，将按照年月部分截取处理）；不能大于最后缴纳月");
        headerCommentMap.put(HeaderConstants.ID_SI_PAY_START, stardOnCellComment);
        headerCommentMap.put(HeaderConstants.ID_HF_PAY_START, stardOnCellComment);

        CellComment endOnCellComment = CellComment.createDefaultCellComment("年-月：如2018-01（如填写年月日，将按照年月部分截取处理）；不能小于起始缴纳月");
        headerCommentMap.put(HeaderConstants.ID_SI_PAY_END, endOnCellComment);
        headerCommentMap.put(HeaderConstants.ID_HF_PAY_END, endOnCellComment);
        return headerCommentMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importExcel(String companyId,
                            String userId, ImportRequest importRequest) {
        //******************************************保存员工台账数据********************************************/
        List<StaffBenefitVo> importedStaffBenefitVos = null;
        try {
            importedStaffBenefitVos = importRequest.getConvertResultList();
        } catch (Exception e) {
            logger.error(e.toString());
            ValidationUtils.reject(null, "正确数据导入失败");
        }
        staffBenefitAggregateService.saveBenefits(companyId, userId, importedStaffBenefitVos, StaffDataAuthorityCodeConstants.ARCHIVE_AUTHORITY_CODE_VIEW);
    }

    @Override
    public void exportExcel(String companyId, String userId,
                            StaffBenefitRequest request, ServletOutputStream outputStream) {
        ExportParams<List<Object>> exportParams = new ExportParams();
        Map<String, String> headerMap = getTemplateHeaderMap(true);
        exportParams.setHeaderMap(headerMap);

        PageData<StaffBenefitVo> allData = staffBenefitAggregateService.getList(companyId, userId, request, StaffDataAuthorityCodeConstants.ARCHIVE_AUTHORITY_CODE_VIEW);
        List<List<Object>> excelData = getExcelData(companyId, allData.getContent());
        exportParams.setRowDatas(excelData);
        try {
            ExcelUtil.exportExcel(exportParams, outputStream);
            outputStream.close();
        } catch (IOException e) {
            ValidationUtils.reject("", "数据导出失败,请刷新重试");
            logger.info(e.getMessage());
        }
    }

    /**
     * @param companyId
     * @param data
     * @return
     */
    private List<List<Object>> getExcelData(String companyId, List<StaffBenefitVo> data) {
        if (CollectionUtils.isEmpty(data)) {
            return Collections.emptyList();
        }

        List<CompanyStructureEntity> companyStructures = organizationService.getCompanyStructure(companyId);
        Map<Long, String> departmentIdNameMap = companyStructures.stream().collect(
                Collectors.toMap(CompanyStructureEntity::getDepartmentId, CompanyStructureEntity::getDepartmentName));
        Map<Long, String> departmentFullNames = organizationService.getDepartmentFullNames(companyId);

        List<CompanyBenefitSimpleVo> companyBenefits = insuranceService.getCompanyBenefits(companyId);
        Map<Long, String> siIdNameMap = Maps.newHashMap();
        Map<Long, String> hfIdNameMap = Maps.newHashMap();
        companyBenefits.forEach(item -> {
            if (item.getCategory() == BenefitCategory.SI) {
                siIdNameMap.put(item.getId(), item.getName());
            } else if (item.getCategory() == BenefitCategory.HF) {
                hfIdNameMap.put(item.getId(), item.getName());
            }
        });

        SimpleDateFormat dateFormat = new SimpleDateFormat(DateUtils.STANDARD_DATE_FORMAT_YM1);

        List<List<Object>> result = Lists.newArrayListWithCapacity(data.size());
        data.forEach(row -> {
            List<Object> rowData = Lists.newArrayList();
            BasicStaffInfoEntity staff = row.getStaff();
            rowData.add(staff.getStaffName());
            rowData.add(staff.getMobileNo());
            rowData.add(staff.getIdCardNo());
            rowData.add(departmentFullNames.get(staff.getDepartmentId()));

            BenefitVo socialInsurance = row.getSocialInsurance();
            if (socialInsurance != null) {
                rowData.add(siIdNameMap.get(socialInsurance.getCompanyBenefitId()));
                rowData.add(socialInsurance.getBase() == null ? null : socialInsurance.getBase() / 100.0);
                rowData.add(getFormatDateStr(dateFormat, socialInsurance.getStartOn()));
                rowData.add(getFormatDateStr(dateFormat, socialInsurance.getEndOn()));
                rowData.add(calculatableNameMap.get(socialInsurance.getCalculatable()));
                rowData.add(departmentIdNameMap.get(socialInsurance.getPayDepartmentId()));
                rowData.add(socialInsurance.getActualPayer() == null ? null : socialInsurance.getActualPayer().getTitle());
            } else {
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
            }

            BenefitVo houseFund = row.getHouseFund();
            if (houseFund != null) {
                rowData.add(hfIdNameMap.get(houseFund.getCompanyBenefitId()));
                rowData.add(houseFund.getBase() == null ? null : houseFund.getBase() / 100.0);
                rowData.add(getFormatDateStr(dateFormat, houseFund.getStartOn()));
                rowData.add(getFormatDateStr(dateFormat, houseFund.getEndOn()));
                rowData.add(calculatableNameMap.get(houseFund.getCalculatable()));
                rowData.add(departmentIdNameMap.get(houseFund.getPayDepartmentId()));
                rowData.add(houseFund.getActualPayer() == null ? null : houseFund.getActualPayer().getTitle());
            } else {
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
                rowData.add(null);
            }
            result.add(rowData);
        });
        return result;
    }

    private String getFormatDateStr(SimpleDateFormat dateFormat, Date date) {
        if (date == null) {
            return null;
        }
        return dateFormat.format(date);
    }


    @Override
    public CustomSpreadSheetValidateResult validateExcelData(String companyId,
                                                             SpreadSheetValidatorRequest validatorRequest) {
        CustomSpreadSheetValidateResult result = new CustomSpreadSheetValidateResult();
        List<SpreadSheetRow> excelDatas = validatorRequest.getSpreadSheetDatas();

        List<CompanyStructureEntity> companyStructures = organizationService.getCompanyStructure(companyId);
        Map<String, Long> departmentNameIdMap = companyStructures.stream().collect(
                Collectors.toMap(CompanyStructureEntity::getDepartmentName, CompanyStructureEntity::getDepartmentId));

        List<CompanyBenefitSimpleVo> companyBenefits = insuranceService.getCompanyBenefits(companyId);
        Map<String, CompanyBenefitSimpleVo> siBenefitNameMap = Maps.newHashMap();
        Map<String, CompanyBenefitSimpleVo> hfBenefitNameMap = Maps.newHashMap();
        companyBenefits.forEach(item -> {
            if (item.getCategory() == BenefitCategory.SI) {
                siBenefitNameMap.put(item.getName(), item);
            } else if (item.getCategory() == BenefitCategory.HF) {
                hfBenefitNameMap.put(item.getName(), item);
            }
        });

        //校验数据
        Map<String, SpreadSheetRow> staffIdRowMap = checkData(departmentNameIdMap, siBenefitNameMap, hfBenefitNameMap,
                excelDatas, result);
        if (CollectionUtils.isEmpty(staffIdRowMap)) {
            return result;
        }

        List<StaffBenefitVo> staffBenefitVos = convertData(companyId, departmentNameIdMap,
                siBenefitNameMap, hfBenefitNameMap, staffIdRowMap);
        try {
            result.setConvertResult(SpreadSheetConvertResultUtil.ObjectToByte(staffBenefitVos));
        } catch (IOException e) {
            logger.error(e.toString());
            ValidationUtils.reject(null, "可导入的正确数据保存失败");
        }
        return result;
    }

    private void addRowLog(CustomSpreadSheetValidateResult result, Integer rowNum, Integer colNum, String log) {
        if (result.getErrors() == null) {
            result.setErrors(Lists.newArrayList());
        }
        SpreadSheetValidatorError error = new SpreadSheetValidatorError();
        error.setRowNum(rowNum);
        error.setColNum(colNum);
        error.setMsg(log);
        result.getErrors().add(error);
    }

    private static final int BASE_MAX = 99999999;

    /**
     * 校验数据
     *
     * @param departmentNameIdMap
     * @param siBenefitNameMap
     * @param hfBenefitNameMap
     * @param excelRows
     * @param result
     * @return
     */
    private Map<String, SpreadSheetRow> checkData(Map<String, Long> departmentNameIdMap,
                                                  Map<String, CompanyBenefitSimpleVo> siBenefitNameMap,
                                                  Map<String, CompanyBenefitSimpleVo> hfBenefitNameMap,
                                                  List<SpreadSheetRow> excelRows,
                                                  CustomSpreadSheetValidateResult result) {
        if (CollectionUtils.isEmpty(excelRows)) {
            return Maps.newHashMap();
        }

        Map<String, SpreadSheetRow> staffIdMap = Maps.newLinkedHashMap();
        excelRows.forEach(row -> {
            List<SpreadSheetCell> cells = row.getCells();
            Map<String, SpreadSheetCell> headerNameMap = cells.stream()
                    .filter(cell -> cell.getCellValue() != null)
                    .collect(Collectors.toMap(SpreadSheetCell::getHeaderName, s -> s));
            Integer rowNum = row.getRowNum();

            boolean siDataError = checkSiData(departmentNameIdMap, siBenefitNameMap, headerNameMap, rowNum, result);
            boolean hfDataError = checkHfData(departmentNameIdMap, hfBenefitNameMap, headerNameMap, rowNum, result);
            if (siDataError || hfDataError) {
                return;
            }
            staffIdMap.put(row.getStaffId(), row);
        });
        return staffIdMap;
    }

    private boolean checkSiData(Map<String, Long> departmentNameIdMap,
                                Map<String, CompanyBenefitSimpleVo> siBenefitNameMap,
                                Map<String, SpreadSheetCell> headerNameMap,
                                Integer rowNum, CustomSpreadSheetValidateResult result) {
        boolean hasError = false;
        SpreadSheetCell siNameCell = headerNameMap.get(HeaderConstants.SI_NAME);
        //社保方案
        if (siNameCell != null
                && !siBenefitNameMap.containsKey(siNameCell.getCellValue().toString())) {
            addRowLog(result, rowNum, siNameCell.getColNum(), "【社保方案】无效");
            hasError = true;
        }
        //社保申报基数
        SpreadSheetCell siBaseCell = headerNameMap.get(HeaderConstants.SI_BASE);
        if (siBaseCell != null) {
            double siBase = 0;
            try {
                siBase = Double.parseDouble(siBaseCell.getCellValue().toString());
            } catch (NumberFormatException e) {
                addRowLog(result, rowNum, siBaseCell.getColNum(), "【社保申报基数】不是有效的数字类型");
                hasError = true;
            }
            if (siBase < 0) {
                addRowLog(result, rowNum, siBaseCell.getColNum(), "【社保申报基数】不能小于0");
                hasError = true;
            }
            if (siBase > BASE_MAX) {
                addRowLog(result, rowNum, siBaseCell.getColNum(), "【社保申报基数】不能大于99999999");
                hasError = true;
            }
        }

        //社保起始缴纳月
        SpreadSheetCell siStartOnCell = headerNameMap.get(HeaderConstants.SI_PAY_START);
        //社保最后缴纳月
        SpreadSheetCell siEndOnCell = headerNameMap.get(HeaderConstants.SI_PAY_END);
        if (siStartOnCell != null && siEndOnCell != null) {
            Date siStartOn = DateUtils.parse(siStartOnCell.getCellValue().toString());
            Date siEndOn = DateUtils.parse(siEndOnCell.getCellValue().toString());
            if (siStartOn == null) {
                addRowLog(result, rowNum, siStartOnCell.getColNum(), "【社保起始缴纳月】无效");
                hasError = true;
            }
            if (siEndOn == null) {
                addRowLog(result, rowNum, siStartOnCell.getColNum(), "【社保最后缴纳月】无效");
                hasError = true;
            }
            if (siStartOn != null && siEndOn != null
                    && DateUtils.getYearMonthDate(siStartOn).after(DateUtils.getYearMonthDate(siEndOn))) {
                addRowLog(result, rowNum, siStartOnCell.getColNum(), "【社保起始缴纳月】不能大于【社保最后缴纳月】");
                hasError = true;
            }
        }

        //社保缴纳组织
        SpreadSheetCell siPayOrganizationCell = headerNameMap.get(HeaderConstants.SI_PAY_ORGANIZATION);
        if (siPayOrganizationCell != null
                && !departmentNameIdMap.containsKey(siPayOrganizationCell.getCellValue().toString())) {
            addRowLog(result, rowNum, siPayOrganizationCell.getColNum(), "【社保缴纳组织】无效");
            hasError = true;
        }
        return hasError;
    }

    private boolean checkHfData(Map<String, Long> departmentNameIdMap,
                                Map<String, CompanyBenefitSimpleVo> hfBenefitNameMap,
                                Map<String, SpreadSheetCell> headerNameMap,
                                Integer rowNum, CustomSpreadSheetValidateResult result) {
        boolean hasError = false;
        //公积金方案
        SpreadSheetCell hfNameCell = headerNameMap.get(HeaderConstants.HF_NAME);
        if (hfNameCell != null
                && !hfBenefitNameMap.containsKey(hfNameCell.getCellValue().toString())) {
            addRowLog(result, rowNum, hfNameCell.getColNum(), "【公积金方案】无效");
            hasError = true;
        }

        //公积金申报基数
        SpreadSheetCell hfBaseCell = headerNameMap.get(HeaderConstants.HF_BASE);
        if (hfBaseCell != null) {
            double hfBase = 0;
            try {
                hfBase = Double.parseDouble(hfBaseCell.getCellValue().toString());
            } catch (NumberFormatException e) {
                addRowLog(result, rowNum, hfBaseCell.getColNum(), "【公积金申报基数】不是有效的数字");
                hasError = true;
            }
            if (hfBase < 0) {
                addRowLog(result, rowNum, hfBaseCell.getColNum(), "【公积金申报基数】不能小于0");
                hasError = true;
            }
            if (hfBase > BASE_MAX) {
                addRowLog(result, rowNum, hfBaseCell.getColNum(), "【公积金申报基数】不能大于99999999");
                hasError = true;
            }
        }

        //公积金起始缴纳月
        SpreadSheetCell hfStartOnCell = headerNameMap.get(HeaderConstants.HF_PAY_START);
        //公积金最后缴纳月
        SpreadSheetCell hfEndOnCell = headerNameMap.get(HeaderConstants.HF_PAY_END);
        if (hfStartOnCell != null && hfEndOnCell != null) {
            Date hfStartOn = DateUtils.parse(hfStartOnCell.getCellValue().toString());
            Date hfEndOn = DateUtils.parse(hfEndOnCell.getCellValue().toString());
            if (hfStartOn == null) {
                addRowLog(result, rowNum, hfStartOnCell.getColNum(), "【公积金起始缴纳月】无效");
                hasError = true;
            }
            if (hfEndOn == null) {
                addRowLog(result, rowNum, hfStartOnCell.getColNum(), "【公积金最后缴纳月】无效");
                hasError = true;
            }
            if (hfStartOn != null && hfEndOn != null
                    && DateUtils.getYearMonthDate(hfStartOn).after(DateUtils.getYearMonthDate(hfEndOn))) {
                addRowLog(result, rowNum, hfStartOnCell.getColNum(), "【公积金起始缴纳月】不能大于【公积金最后缴纳月】");
                hasError = true;
            }
        }

        //公积金缴纳组织
        SpreadSheetCell hfPayOrganizationCell = headerNameMap.get(HeaderConstants.HF_PAY_ORGANIZATION);
        if (hfPayOrganizationCell != null
                && !departmentNameIdMap.containsKey(hfPayOrganizationCell.getCellValue().toString())) {
            addRowLog(result, rowNum, hfPayOrganizationCell.getColNum(), "【公积金缴纳组织】无效");
            hasError = true;
        }
        return hasError;
    }

    private List<StaffBenefitVo> convertData(String companyId,
                                             Map<String, Long> departmentNameIdMap,
                                             Map<String, CompanyBenefitSimpleVo> siBenefitNameMap,
                                             Map<String, CompanyBenefitSimpleVo> hfBenefitNameMap,
                                             Map<String, SpreadSheetRow> staffIdExcelRowMap) {
        if (CollectionUtils.isEmpty(staffIdExcelRowMap)) {
            return Lists.newArrayList();
        }
        //获取已经存在的员工数据
        List<String> importedStaffIds = Lists.newArrayList(staffIdExcelRowMap.keySet());
        List<StaffBenefitVo> existedStaffBenefits = insuranceService.getAllStaffBenefitInclude(companyId, new StaffIdRequest(importedStaffIds));
        Map<String, StaffBenefitVo> existedStaffBenefitMap = Maps.newHashMap();
        existedStaffBenefits.forEach(item -> existedStaffBenefitMap.put(item.getStaff().getId(), item));

        List<StaffBenefitVo> importedStaffBenefitVos = Lists.newArrayList();

        staffIdExcelRowMap.forEach((staffId, row) -> {
            StaffBenefitVo benefitVo = existedStaffBenefitMap.get(staffId);
            if (benefitVo == null) {
                benefitVo = new StaffBenefitVo();
                benefitVo.setStaff(new BasicStaffInfoEntity(staffId));
            }

            Map<String, Object> nameValueMap = row.getCells().stream()
                    .filter(cell -> cell.getCellValue() != null)
                    .collect(Collectors.toMap(SpreadSheetCell::getHeaderName, SpreadSheetCell::getCellValue));

            updateSiInfo(departmentNameIdMap, siBenefitNameMap, benefitVo, nameValueMap);
            updateHfInfo(departmentNameIdMap, hfBenefitNameMap, benefitVo, nameValueMap);

            importedStaffBenefitVos.add(benefitVo);
        });
        return importedStaffBenefitVos;
    }

    /**
     * 设置社保相关数据
     *
     * @param departmentNameIdMap
     * @param siBenefitNameMap
     * @param benefitVo
     * @param nameValueMap
     */
    private void updateSiInfo(Map<String, Long> departmentNameIdMap,
                              Map<String, CompanyBenefitSimpleVo> siBenefitNameMap,
                              StaffBenefitVo benefitVo, Map<String, Object> nameValueMap) {
        //社保
        if (benefitVo.getSocialInsurance() == null) {
            benefitVo.setSocialInsurance(new BenefitVo());
        }
        BenefitVo socialInsurance = benefitVo.getSocialInsurance();

        //社保方案
        String siName = nameValueMap.get(HeaderConstants.SI_NAME) == null
                ? null : nameValueMap.get(HeaderConstants.SI_NAME).toString();
        if (siBenefitNameMap.containsKey(siName)) {
            socialInsurance.setCompanyBenefitId(siBenefitNameMap.get(siName).getId());
            socialInsurance.setDivisionId(siBenefitNameMap.get(siName).getDivisionId());
        }

        //社保申报基数
        Object siBase = nameValueMap.get(HeaderConstants.SI_BASE);
        if (siBase instanceof Double) {
            socialInsurance.setBase((int) (((Double) siBase) * 100));
        }

        //社保起始缴纳月
        Object siStartOn = nameValueMap.get(HeaderConstants.SI_PAY_START);
        if (siStartOn != null) {
            Date siStartOnDate = DateUtils.parse(siStartOn.toString());
            Date siStartOnYearMonthDate = DateUtils.getYearMonthDate(siStartOnDate);
            socialInsurance.setStartOn(siStartOnYearMonthDate);
        }

        //社保最后缴纳月
        Object siEndOn = nameValueMap.get(HeaderConstants.SI_PAY_END);
        if (siEndOn != null) {
            Date siEndOnDate = DateUtils.parse(siEndOn.toString());
            Date siEndOnYearMonthDate = DateUtils.getYearMonthDate(siEndOnDate);
            socialInsurance.setEndOn(siEndOnYearMonthDate);
        }

        //社保是否计算
        String siCalculatable = nameValueMap.get(HeaderConstants.SI_CALCULATE) == null
                ? null : nameValueMap.get(HeaderConstants.SI_CALCULATE).toString();
        if (calculates.containsKey(siCalculatable)) {
            socialInsurance.setCalculatable(calculates.get(siCalculatable));
        }

        //社保缴纳组织
        String siPayDepartmentName = nameValueMap.get(HeaderConstants.SI_PAY_ORGANIZATION) == null
                ? null : nameValueMap.get(HeaderConstants.SI_PAY_ORGANIZATION).toString();
        if (departmentNameIdMap.containsKey(siPayDepartmentName)) {
            socialInsurance.setPayDepartmentId(departmentNameIdMap.get(siPayDepartmentName));
        }

        //社保实际承担方
        Object siActualPayer = nameValueMap.get(HeaderConstants.SI_PAYER_ACTUAL);
        if (siActualPayer != null) {
            socialInsurance.setActualPayer(payers.get(siActualPayer.toString()));
        }
    }

    /**
     * 设置公积金相关数据
     *
     * @param departmentNameIdMap
     * @param hfBenefitNameMap
     * @param benefitVo
     * @param nameValueMap
     */
    private void updateHfInfo(Map<String, Long> departmentNameIdMap,
                              Map<String, CompanyBenefitSimpleVo> hfBenefitNameMap,
                              StaffBenefitVo benefitVo, Map<String, Object> nameValueMap) {
        //公积金
        if (benefitVo.getHouseFund() == null) {
            benefitVo.setHouseFund(new BenefitVo());
        }
        BenefitVo houseFund = benefitVo.getHouseFund();

        //公积金方案
        String hfName = nameValueMap.get(HeaderConstants.HF_NAME) == null
                ? null : nameValueMap.get(HeaderConstants.HF_NAME).toString();
        if (hfBenefitNameMap.containsKey(hfName)) {
            houseFund.setCompanyBenefitId(hfBenefitNameMap.get(hfName).getId());
            houseFund.setDivisionId(hfBenefitNameMap.get(hfName).getDivisionId());
        }

        //公积金申报基数
        Object hfBase = nameValueMap.get(HeaderConstants.HF_BASE);
        if (hfBase instanceof Double) {
            houseFund.setBase((int) (((Double) hfBase) * 100));
        }

        //公积金起始缴纳月
        Object hfStartOn = nameValueMap.get(HeaderConstants.HF_PAY_START);
        if (hfStartOn != null) {
            Date hfStartOnDate = DateUtils.parse(hfStartOn.toString());
            Date hfStartOnYearMonthDate = DateUtils.getYearMonthDate(hfStartOnDate);
            houseFund.setStartOn(hfStartOnYearMonthDate);
        }

        //公积金最后缴纳月
        Object hfEndOn = nameValueMap.get(HeaderConstants.HF_PAY_END);
        if (hfEndOn != null) {
            Date hfEndOnDate = DateUtils.parse(hfEndOn.toString());
            Date hfEndOnYearMonthDate = DateUtils.getYearMonthDate(hfEndOnDate);
            houseFund.setEndOn(hfEndOnYearMonthDate);
        }

        //公积金是否计算
        String hfCalculatable = nameValueMap.get(HeaderConstants.HF_CALCULATE) == null
                ? null : nameValueMap.get(HeaderConstants.HF_CALCULATE).toString();
        if (calculates.containsKey(hfCalculatable)) {
            houseFund.setCalculatable(calculates.get(hfCalculatable));
        }

        //公积金缴纳组织
        String hfPayDepartmentName = nameValueMap.get(HeaderConstants.HF_PAY_ORGANIZATION) == null
                ? null : nameValueMap.get(HeaderConstants.HF_PAY_ORGANIZATION).toString();
        if (departmentNameIdMap.containsKey(hfPayDepartmentName)) {
            houseFund.setPayDepartmentId(departmentNameIdMap.get(hfPayDepartmentName));
        }

        //公积金实际承担方
        Object hfActualPayer = nameValueMap.get(HeaderConstants.HF_PAYER_ACTUAL);
        if (hfActualPayer != null) {
            houseFund.setActualPayer(payers.get(hfActualPayer.toString()));
        }
    }

    private Map<String, String> getTemplateHeaderMap(boolean export) {
        Map<String, String> headerMap = new LinkedHashMap<>();
        headerMap.put(HeaderConstants.ID_NAME, HeaderConstants.NAME);
        headerMap.put(HeaderConstants.ID_MOBILE_NO, HeaderConstants.MOBILE_NO);
        if (export) {
            headerMap.put(HeaderConstants.ID_ID_CARD_NO, HeaderConstants.ID_CARD_NO);
            headerMap.put(HeaderConstants.ID_DEPARTMENT_NAME, HeaderConstants.DEPARTMENT_NAME);
        }

        headerMap.put(HeaderConstants.ID_SI_NAME, HeaderConstants.SI_NAME);
        headerMap.put(HeaderConstants.ID_SI_BASE, HeaderConstants.SI_BASE);
        headerMap.put(HeaderConstants.ID_SI_PAY_START, HeaderConstants.SI_PAY_START);
        headerMap.put(HeaderConstants.ID_SI_PAY_END, HeaderConstants.SI_PAY_END);
        headerMap.put(HeaderConstants.ID_SI_CALCULATE, HeaderConstants.SI_CALCULATE);
        headerMap.put(HeaderConstants.ID_SI_PAY_ORGANIZATION, HeaderConstants.SI_PAY_ORGANIZATION);
        headerMap.put(HeaderConstants.ID_SI_PAYER_ACTUAL, HeaderConstants.SI_PAYER_ACTUAL);

        headerMap.put(HeaderConstants.ID_HF_NAME, HeaderConstants.HF_NAME);
        headerMap.put(HeaderConstants.ID_HF_BASE, HeaderConstants.HF_BASE);
        headerMap.put(HeaderConstants.ID_HF_PAY_START, HeaderConstants.HF_PAY_START);
        headerMap.put(HeaderConstants.ID_HF_PAY_END, HeaderConstants.HF_PAY_END);
        headerMap.put(HeaderConstants.ID_HF_CALCULATE, HeaderConstants.HF_CALCULATE);
        headerMap.put(HeaderConstants.ID_HF_PAY_ORGANIZATION, HeaderConstants.HF_PAY_ORGANIZATION);
        headerMap.put(HeaderConstants.ID_HF_PAYER_ACTUAL, HeaderConstants.HF_PAYER_ACTUAL);

        return headerMap;
    }

    private Map<String, ExcelCellStyle> getHeaderStyleMap() {
        ExcelCellStyle requiredStyle = ExcelCellStyleFactory.createRequiredHeaderCellStyle();
        Map<String, ExcelCellStyle> headerStyleMap = Maps.newHashMap();
        headerStyleMap.put(HeaderConstants.ID_NAME, requiredStyle);
        return headerStyleMap;
    }

    private Map<String, List<String>> getDropDownsMap(@Nonnull String companyId) {
        Map<String, List<String>> dropDownsMap = Maps.newLinkedHashMap();

        List<CompanyBenefitSimpleVo> companyBenefits = insuranceService.getCompanyBenefits(companyId);

        List<String> siBenefitNames = companyBenefits.stream()
                .filter(vo -> vo.getCategory() == BenefitCategory.SI)
                .map(CompanyBenefitSimpleVo::getName).collect(Collectors.toList());
        dropDownsMap.put(HeaderConstants.ID_SI_NAME, siBenefitNames);

        List<CompanyStructureEntity> companyStructures = Lists.newArrayList();
        try {
            companyStructures = organizationService.getCompanyStructure(companyId);
        } catch (Exception e) {
            logger.error("调用组织架构服务失败：" + e);
            ValidationUtils.reject(null, "调用组织架构服务失败");
        }
        List<String> departmentNames = companyStructures.stream().map(CompanyStructureEntity::getDepartmentName).collect(Collectors.toList());
        dropDownsMap.put(HeaderConstants.ID_SI_PAY_ORGANIZATION, departmentNames);

        dropDownsMap.put(HeaderConstants.ID_SI_CALCULATE, calculateList);

        dropDownsMap.put(HeaderConstants.ID_SI_PAYER_ACTUAL, payerTitles);

        List<String> hfBenefitNames = companyBenefits.stream()
                .filter(vo -> vo.getCategory() == BenefitCategory.HF)
                .map(CompanyBenefitSimpleVo::getName).collect(Collectors.toList());
        dropDownsMap.put(HeaderConstants.ID_HF_NAME, hfBenefitNames);

        dropDownsMap.put(HeaderConstants.ID_HF_PAY_ORGANIZATION, departmentNames);

        dropDownsMap.put(HeaderConstants.ID_HF_CALCULATE, calculateList);

        dropDownsMap.put(HeaderConstants.ID_HF_PAYER_ACTUAL, payerTitles);

        return dropDownsMap;
    }
}
